<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SQL脱敏工具</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3b82f6',
                        secondary: '#10b981',
                        neutral: '#64748b',
                        danger: '#ef4444',
                    },
                    fontFamily: {
                        inter: ['Inter', 'system-ui', 'sans-serif'],
                        mono: ['JetBrains Mono', 'Consolas', 'Monaco', 'monospace'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .editor-shadow {
                box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
            }
            .btn-hover {
                @apply transition-all duration-200 hover:shadow-md;
            }
            .sql-keyword {
                @apply text-blue-600 font-medium;
            }
            .sql-literal {
                @apply text-green-600;
            }
            .sql-comment {
                @apply text-gray-500 italic;
            }
            .table-row-animate {
                @apply transition-all duration-300;
            }
            .highlight-row {
                @apply bg-primary/5;
            }
            .sortable-header {
                @apply cursor-pointer relative;
            }
            .sortable-header::after {
                content: '';
                @apply absolute right-0 top-1/2 transform -translate-y-1/2 w-4 h-4 opacity-50;
            }
            .sort-asc::after {
                background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 15l7-7 7 7' /%3E%3C/svg%3E");
            }
            .sort-desc::after {
                background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='currentColor'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7' /%3E%3C/svg%3E");
            }
        }
    </style>
</head>
<body class="font-inter bg-gray-50 text-gray-800 min-h-screen flex flex-col">
    <!-- 顶部导航 -->
    <header class="bg-white border-b border-gray-200 shadow-sm">
        <div class="container mx-auto px-4 py-4 flex justify-between items-center">
            <div class="flex items-center space-x-2">
                <i class="fa fa-database text-primary text-2xl"></i>
                <h1 class="text-xl font-bold text-gray-800">SQL脱敏工具</h1>
            </div>
            <div class="flex items-center space-x-4">
                <button id="copyResultBtn" class="flex items-center space-x-1 text-sm text-neutral hover:text-primary transition-colors">
                    <i class="fa fa-clipboard"></i>
                    <span>复制结果</span>
                </button>
                <button id="clearBtn" class="flex items-center space-x-1 text-sm text-neutral hover:text-danger transition-colors">
                    <i class="fa fa-trash"></i>
                    <span>清空</span>
                </button>
            </div>
        </div>
    </header>
    <!-- 主内容区 -->
    <main class="flex-grow container mx-auto px-4 py-8">
        <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
            <!-- 输入区域 -->
            <div class="bg-white rounded-xl p-6 editor-shadow">
                <div class="flex justify-between items-center mb-4">
                    <h2 class="text-lg font-semibold text-gray-700">原始SQL</h2>
                    <div class="flex space-x-2">
                        <button id="exampleBtn" class="px-3 py-1 text-xs bg-gray-100 hover:bg-gray-200 rounded-md btn-hover">
                            <i class="fa fa-lightbulb-o mr-1"></i>示例
                        </button>
                        <button id="formatBtn" class="px-3 py-1 text-xs bg-gray-100 hover:bg-gray-200 rounded-md btn-hover">
                            <i class="fa fa-indent mr-1"></i>格式化
                        </button>
                    </div>
                </div>
                <div class="relative">
                    <textarea id="sqlInput" class="w-full h-64 p-4 bg-gray-50 border border-gray-200 rounded-lg focus:ring-2 focus:ring-primary/30 focus:border-primary outline-none resize-none font-mono text-sm" placeholder="请粘贴SQL语句..."></textarea>
                    <div id="charCount" class="absolute bottom-3 right-3 text-xs text-gray-400">0 字符</div>
                </div>
            </div>
            <!-- 输出区域 -->
            <div class="bg-white rounded-xl p-6 editor-shadow">
                <div class="flex justify-between items-center mb-4">
                    <h2 class="text-lg font-semibold text-gray-700">脱敏后SQL</h2>
                    <div class="flex space-x-2">
                        <button id="copyBtn" class="px-3 py-1 text-xs bg-gray-100 hover:bg-gray-200 rounded-md btn-hover">
                            <i class="fa fa-clipboard mr-1"></i>复制
                        </button>
                        <button id="downloadBtn" class="px-3 py-1 text-xs bg-gray-100 hover:bg-gray-200 rounded-md btn-hover">
                            <i class="fa fa-download mr-1"></i>下载
                        </button>
                    </div>
                </div>
                <div class="relative">
                    <pre id="sqlOutput" class="w-full h-64 p-4 bg-gray-50 border border-gray-200 rounded-lg overflow-auto font-mono text-sm"></pre>
                    <div id="outputCharCount" class="absolute bottom-3 right-3 text-xs text-gray-400">0 字符</div>
                </div>
            </div>
        </div>
        <!-- 配置选项 -->
        <div class="bg-white rounded-xl p-6 mt-8 editor-shadow">
            <h2 class="text-lg font-semibold text-gray-700 mb-4">脱敏选项</h2>
            <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
                <div class="flex items-center space-x-2">
                    <input type="checkbox" id="inClause" class="rounded text-primary focus:ring-primary" checked>
                    <label for="inClause" class="text-sm text-gray-700">处理IN子句</label>
                </div>
                <div class="flex items-center space-x-2">
                    <input type="checkbox" id="likeClause" class="rounded text-primary focus:ring-primary" checked>
                    <label for="likeClause" class="text-sm text-gray-700">处理LIKE条件</label>
                </div>
                <div class="flex items-center space-x-2">
                    <input type="checkbox" id="stringLiterals" class="rounded text-primary focus:ring-primary" checked>
                    <label for="stringLiterals" class="text-sm text-gray-700">处理字符串</label>
                </div>
                <div class="flex items-center space-x-2">
                    <input type="checkbox" id="numbers" class="rounded text-primary focus:ring-primary" checked>
                    <label for="numbers" class="text-sm text-gray-700">处理数字</label>
                </div>
                <div class="flex items-center space-x-2">
                    <input type="checkbox" id="dates" class="rounded text-primary focus:ring-primary" checked>
                    <label for="dates" class="text-sm text-gray-700">处理日期</label>
                </div>
                <div class="flex items-center space-x-2">
                    <input type="checkbox" id="booleans" class="rounded text-primary focus:ring-primary" checked>
                    <label for="booleans" class="text-sm text-gray-700">处理布尔值</label>
                </div>
            </div>
            
            <div class="mt-6 flex justify-between">
                <div class="text-sm text-gray-500">
                    <i class="fa fa-info-circle mr-1"></i>
                    <span>脱敏规则：</span>
                    <span class="text-xs">字符串 → '?', 数字 → ?, 日期 → DATE(?), 布尔 → ?</span>
                </div>
                <button id="desensitizeBtn" class="px-6 py-2 bg-primary hover:bg-primary/90 text-white rounded-md btn-hover flex items-center space-x-2">
                    <i class="fa fa-magic"></i>
                    <span>执行脱敏</span>
                </button>
            </div>
        </div>
        <!-- 统计表格 -->
        <div class="bg-white rounded-xl p-6 mt-8 editor-shadow">
            <div class="flex justify-between items-center mb-4">
                <h2 class="text-lg font-semibold text-gray-700">SQL执行统计</h2>
                <div class="flex items-center space-x-2">
                    <div class="text-sm text-gray-500">
                        <span id="totalQueries">0</span> 个查询，
                        <span id="uniqueQueries">0</span> 个唯一SQL
                    </div>
                    <button id="exportTableBtn" class="px-3 py-1 text-xs bg-gray-100 hover:bg-gray-200 rounded-md btn-hover">
                        <i class="fa fa-download mr-1"></i>导出表格
                    </button>
                </div>
            </div>
            <div class="overflow-x-auto">
                <table class="min-w-full divide-y divide-gray-200">
                    <thead class="bg-gray-50">
                        <tr>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">排名</th>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider sortable-header" data-sort="count">执行次数</th>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider sortable-header" data-sort="avgTime">平均时间</th>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider sortable-header" data-sort="totalTime">总时间</th>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider sortable-header" data-sort="percentage">百分比</th>
                            <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">脱敏后SQL</th>
                        </tr>
                    </thead>
                    <tbody id="statsTable" class="bg-white divide-y divide-gray-200">
                        <!-- 统计结果将在这里动态生成 -->
                        <tr>
                            <td colspan="6" class="px-6 py-12 text-center text-gray-500">
                                <div class="flex flex-col items-center">
                                    <i class="fa fa-bar-chart text-4xl mb-4 text-gray-300"></i>
                                    <p>执行脱敏后，统计结果将显示在这里</p>
                                </div>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
        <!-- 结果统计 -->
        <div class="grid grid-cols-1 md:grid-cols-4 gap-4 mt-8">
            <div class="bg-white rounded-xl p-5 editor-shadow">
                <div class="flex items-center justify-between">
                    <h3 class="text-sm font-medium text-gray-500">原始长度</h3>
                    <span id="originalLength" class="text-2xl font-bold text-gray-800">0</span>
                </div>
                <div class="mt-2 text-xs text-gray-400">字符数</div>
            </div>
            <div class="bg-white rounded-xl p-5 editor-shadow">
                <div class="flex items-center justify-between">
                    <h3 class="text-sm font-medium text-gray-500">脱敏后长度</h3>
                    <span id="desensitizedLength" class="text-2xl font-bold text-gray-800">0</span>
                </div>
                <div class="mt-2 text-xs text-gray-400">字符数</div>
            </div>
            <div class="bg-white rounded-xl p-5 editor-shadow">
                <div class="flex items-center justify-between">
                    <h3 class="text-sm font-medium text-gray-500">参数数量</h3>
                    <span id="parameterCount" class="text-2xl font-bold text-primary">0</span>
                </div>
                <div class="mt-2 text-xs text-gray-400">已替换的参数</div>
            </div>
            <div class="bg-white rounded-xl p-5 editor-shadow">
                <div class="flex items-center justify-between">
                    <h3 class="text-sm font-medium text-gray-500">压缩率</h3>
                    <span id="compressionRate" class="text-2xl font-bold text-secondary">0%</span>
                </div>
                <div class="mt-2 text-xs text-gray-400">长度减少比例</div>
            </div>
        </div>
    </main>
    <!-- 页脚 -->
    <footer class="bg-white border-t border-gray-200 py-4 mt-8">
        <div class="container mx-auto px-4 text-center text-sm text-gray-500">
            <p>SQL脱敏工具 | 用于SQL查询参数的标准化处理</p>
        </div>
    </footer>
    <script>
        // 示例SQL
        const exampleSQL = `Count: 10  Time=3.25s (28s)
SELECT * FROM users WHERE id = 123 AND name = 'John Doe'
Count: 5  Time=1.50s (7.5s)
SELECT * FROM orders WHERE user_id = 123 AND status = 'pending'
Count: 8  Time=4.75s (38s)
SELECT * FROM products WHERE category = 'electronics' AND price > 1000
Count: 10  Time=2.10s (21s)
SELECT * FROM users WHERE id = 456 AND name = 'Jane Smith'
Count: 3  Time=0.75s (2.25s)
SELECT * FROM orders WHERE user_id = 456 AND status = 'completed'`;
        // 全局变量存储统计数据
        let statsMap = new Map();
        let currentStatsArray = [];
        let currentTotalTime = 0;
        let sortField = 'count';
        let sortAsc = false;
        
        // DOM元素
        const sqlInput = document.getElementById('sqlInput');
        const sqlOutput = document.getElementById('sqlOutput');
        const charCount = document.getElementById('charCount');
        const outputCharCount = document.getElementById('outputCharCount');
        const desensitizeBtn = document.getElementById('desensitizeBtn');
        const exampleBtn = document.getElementById('exampleBtn');
        const formatBtn = document.getElementById('formatBtn');
        const copyBtn = document.getElementById('copyBtn');
        const copyResultBtn = document.getElementById('copyResultBtn');
        const clearBtn = document.getElementById('clearBtn');
        const downloadBtn = document.getElementById('downloadBtn');
        const exportTableBtn = document.getElementById('exportTableBtn');
        const inClauseCheckbox = document.getElementById('inClause');
        const likeClauseCheckbox = document.getElementById('likeClause');
        const stringLiteralsCheckbox = document.getElementById('stringLiterals');
        const numbersCheckbox = document.getElementById('numbers');
        const datesCheckbox = document.getElementById('dates');
        const booleansCheckbox = document.getElementById('booleans');
        const originalLength = document.getElementById('originalLength');
        const desensitizedLength = document.getElementById('desensitizedLength');
        const parameterCount = document.getElementById('parameterCount');
        const compressionRate = document.getElementById('compressionRate');
        const statsTable = document.getElementById('statsTable');
        const totalQueries = document.getElementById('totalQueries');
        const uniqueQueries = document.getElementById('uniqueQueries');
        const sortHeaders = document.querySelectorAll('.sortable-header');
        
        // 更新字符计数
        function updateCharCount() {
            charCount.textContent = `${sqlInput.value.length} 字符`;
        }
        
        // 更新结果统计
        function updateStats(original, desensitized, paramCount) {
            originalLength.textContent = original.length;
            desensitizedLength.textContent = desensitized.length;
            parameterCount.textContent = paramCount;
            
            const rate = Math.round((1 - desensitized.length / original.length) * 100);
            compressionRate.textContent = `${rate}%`;
            
            // 添加动画效果
            [originalLength, desensitizedLength, parameterCount, compressionRate].forEach(el => {
                el.classList.add('scale-110');
                setTimeout(() => el.classList.remove('scale-110'), 300);
            });
        }
        
        // SQL脱敏函数
        function desensitizeSQL(sql) {
            if (!sql.trim()) return '';
            
            let result = sql;
            let count = 0;
            
            // 处理注释
            result = result.replace(/(--.*?$|\/\*[\s\S]*?\*\/)/gm, match => {
                count++;
                return '-- ?';
            });
            
            // 处理IN子句
            if (inClauseCheckbox.checked) {
                result = result.replace(/\bIN\s*\(\s*('[^']*'|\"[^\"]*\"|\d+|NULL)(\s*,\s*('[^']*'|\"[^\"]*\"|\d+|NULL))*\s*\)/gi, match => {
                    count++;
                    return 'IN (?)';
                });
            }
            
            // 处理LIKE条件
            if (likeClauseCheckbox.checked) {
                result = result.replace(/\bLIKE\s+('[^']*'|\"[^\"]*\")/gi, match => {
                    count++;
                    return 'LIKE \'%?%\'';
                });
                
                // 处理LIKE CONCAT('%', ?, '%')
                result = result.replace(/\bLIKE\s+CONCAT\(\s*('[^']*'|\"[^\"]*\")\s*,\s*('[^']*'|\"[^\"]*\")\s*,\s*('[^']*'|\"[^\"]*\")\s*\)/gi, match => {
                    count++;
                    return 'LIKE \'%?%\'';
                });
            }
            
            // 处理字符串字面量
            if (stringLiteralsCheckbox.checked) {
                result = result.replace(/'[^']*'/g, () => {
                    count++;
                    return '\'?\'';
                });
                
                result = result.replace(/"[^"]*"/g, () => {
                    count++;
                    return '"?"';
                });
            }
            
            // 处理数字
            if (numbersCheckbox.checked) {
                result = result.replace(/\b\d+\b/g, () => {
                    count++;
                    return '?';
                });
            }
            
            // 处理日期
            if (datesCheckbox.checked) {
                // 匹配标准日期格式 'YYYY-MM-DD'
                result = result.replace(/'(\d{4}-\d{2}-\d{2})( \d{2}:\d{2}:\d{2})?'/g, () => {
                    count++;
                    return 'DATE(?)';
                });
            }
            
            // 处理布尔值
            if (booleansCheckbox.checked) {
                result = result.replace(/\b(true|false|TRUE|FALSE)\b/g, () => {
                    count++;
                    return '?';
                });
            }
            
            return { result, count };
        }
        
        // 解析SQL组（包含Count和Time信息）
        function parseSQLGroups(input) {
            const sqlGroups = [];
            // 分割输入为多个SQL块（按Count:分割）
            const blocks = input.split(/Count:/).filter(block => block.trim());
            
            blocks.forEach(block => {
                // 为每个块重新添加Count:前缀，便于正则匹配
                const fullBlock = `Count:${block}`;
                
                // 匹配Count、单次时间和总时间（忽略中间的其他内容）
                const countMatch = fullBlock.match(/Count:\s*(\d+)/);
                const timeMatch = fullBlock.match(/Time=([\d.]+)s\s*\(([\d.]+)s\)/);
                
                if (!countMatch || !timeMatch) {
                    console.warn('无法解析SQL块:', fullBlock);
                    return;
                }
                
                // 提取并转换为数字（确保是有效数字）
                const count = parseInt(countMatch[1]) || 0;
                const singleTime = parseFloat(timeMatch[1]) || 0;
                const totalTime = parseFloat(timeMatch[2]) || 0;
                
                // 提取SQL内容（Count和Time之后的部分）
                const sqlStartIndex = fullBlock.indexOf(';') > -1 
                    ? fullBlock.indexOf(';') + 1 
                    : fullBlock.search(/SELECT|INSERT|UPDATE|DELETE|CREATE|ALTER|DROP/);
                
                if (sqlStartIndex === -1) {
                    console.warn('未找到SQL语句:', fullBlock);
                    return;
                }
                
                const sql = fullBlock.substring(sqlStartIndex).trim()
                    .replace(/Lock=.*?/g, '')
                    .replace(/Rows=.*?/g, '')
                    .replace(/nfo\[.*?\]@\[.*?\]/g, '')
                    .replace(/\s+/g, ' ')
                    .trim();
                
                if (sql) {
                    const avgTime = count > 0 ? totalTime / count : 0; // 避免除以0
                    sqlGroups.push({
                        count,
                        time: totalTime,       // 总时间
                        avgTime,               // 平均时间
                        singleTime,            // 单次时间
                        sql
                    });
                }
            });
            
            return sqlGroups;
        }
        
        // 格式化SQL（简化版）
        function formatSQL(sql) {
            if (!sql) return '';
            
            // 替换多余空格
            sql = sql.replace(/\s+/g, ' ').trim();
            
            // 定义关键字列表
            const keywords = [
                'SELECT', 'FROM', 'WHERE', 'GROUP BY', 'ORDER BY', 'HAVING', 'JOIN', 
                'LEFT JOIN', 'RIGHT JOIN', 'INNER JOIN', 'OUTER JOIN', 'ON', 'AND', 'OR',
                'INSERT INTO', 'VALUES', 'UPDATE', 'SET', 'DELETE', 'UNION', 'UNION ALL'
            ];
            
            // 按关键字分割SQL
            let formatted = sql;
            keywords.forEach(keyword => {
                const regex = new RegExp(`\\b${keyword}\\b`, 'gi');
                formatted = formatted.replace(regex, `\n${keyword}`);
            });
            
            // 添加缩进
            let lines = formatted.split('\n');
            let indentLevel = 0;
            const indentSize = 2;
            
            lines = lines.map(line => {
                line = line.trim();
                
                // 减少缩进的关键字
                if (/^(WHERE|GROUP BY|ORDER BY|HAVING|ON|AND|OR)$/i.test(line)) {
                    indentLevel = Math.max(0, indentLevel - 1);
                }
                
                const indent = ' '.repeat(indentLevel * indentSize);
                const result = indent + line;
                
                // 增加缩进的关键字
                if (/^(SELECT|FROM|JOIN|LEFT JOIN|RIGHT JOIN|INNER JOIN|OUTER JOIN|INSERT INTO|UPDATE|VALUES|SET|DELETE|UNION|UNION ALL)$/i.test(line)) {
                    indentLevel++;
                }
                
                return result;
            });
            
            return lines.join('\n');
        }
        
        // 执行脱敏并生成统计
        function performDesensitization() {
            let input = sqlInput.value;
            if (!input.trim()) {
                showNotification('请输入SQL语句', 'warning');
                return;
            }
            
            // 过滤干扰项
            input = input.replace(/Lock=[\d.]+s\s*\([\d.]+\s*s\)/g, '')
                         .replace(/Rows=[\d.]+\s*\([\d.]+\)/g, '')
                         .replace(/nfo\[.*?\]@\[.*?\]/g, '')
                         .replace(/\s+/g, ' ').trim();
            
            // 解析SQL组
            const sqlGroups = parseSQLGroups(input);
            
            if (sqlGroups.length === 0) {
                showNotification('未找到有效的SQL组，请确保格式正确', 'warning');
                return;
            }
            
            // 处理每个SQL并生成统计
            statsMap = new Map();
            let allDesensitizedSQL = '';
            let totalParamCount = 0;
            
            sqlGroups.forEach((group) => {
                const { result: desensitizedSQL, count: paramCount } = desensitizeSQL(group.sql);
                totalParamCount += paramCount;
                
                // 添加到总脱敏SQL
                allDesensitizedSQL += `Count: ${group.count}  Time=${group.singleTime}s (${group.time}s)\n`;
                allDesensitizedSQL += desensitizedSQL + '\n\n';
                
                // 更新统计
                if (statsMap.has(desensitizedSQL)) {
                    const stats = statsMap.get(desensitizedSQL);
                    stats.count += group.count;
                    stats.totalTime += group.time;
                    stats.avgTime = stats.count > 0 ? stats.totalTime / stats.count : 0; // 避免除以0
                    stats.queries.push(group);
                } else {
                    statsMap.set(desensitizedSQL, {
                        count: group.count,
                        totalTime: group.time,
                        avgTime: group.avgTime,
                        sql: desensitizedSQL,
                        queries: [group]
                    });
                }
            });
            
            // 转换为数组并排序
            currentStatsArray = Array.from(statsMap.values()).sort((a, b) => b.count - a.count);
            currentTotalTime = currentStatsArray.reduce((sum, stats) => sum + stats.totalTime, 0);
            
            // 更新输出
            sqlOutput.textContent = allDesensitizedSQL.trim();
            outputCharCount.textContent = `${allDesensitizedSQL.length} 字符`;
            
            // 更新统计表格
            renderStatsTable(currentStatsArray, currentTotalTime);
            
            // 更新统计信息
            updateStats(input, allDesensitizedSQL, totalParamCount);
            totalQueries.textContent = sqlGroups.length;
            uniqueQueries.textContent = currentStatsArray.length;
            
            // 添加结果高亮效果
            sqlOutput.classList.add('ring-2', 'ring-primary/30');
            statsTable.classList.add('ring-2', 'ring-primary/30');
            setTimeout(() => {
                sqlOutput.classList.remove('ring-2', 'ring-primary/30');
                statsTable.classList.remove('ring-2', 'ring-primary/30');
            }, 500);
        }
        
        // 渲染统计表格
        function renderStatsTable(statsArray, totalTime) {
            statsTable.innerHTML = '';
            
            // 移除所有排序标识
            sortHeaders.forEach(header => {
                header.classList.remove('sort-asc', 'sort-desc');
            });
            // 添加当前排序标识
            document.querySelector(`[data-sort="${sortField}"]`).classList.add(sortAsc ? 'sort-asc' : 'sort-desc');
            
            if (statsArray.length === 0) {
                statsTable.innerHTML = `
                    <tr>
                        <td colspan="6" class="px-6 py-12 text-center text-gray-500">
                            <div class="flex flex-col items-center">
                                <i class="fa fa-bar-chart text-4xl mb-4 text-gray-300"></i>
                                <p>没有统计数据</p>
                            </div>
                        </td>
                    </tr>
                `;
                return;
            }
            
            statsArray.forEach((stats, index) => {
                // 确保时间值有效
                const safeAvgTime = isNaN(stats.avgTime) ? 0 : stats.avgTime;
                const safeTotalTime = isNaN(stats.totalTime) ? 0 : stats.totalTime;
                const percentage = totalTime > 0 ? ((safeTotalTime / totalTime) * 100).toFixed(1) : 0;
                
                const row = document.createElement('tr');
                row.className = 'table-row-animate hover:bg-gray-50';
                row.setAttribute('data-index', index);
                
                row.innerHTML = `
                    <td class="px-6 py-4 whitespace-nowrap">
                        <div class="flex items-center">
                            <div class="flex-shrink-0 h-8 w-8 flex items-center justify-center rounded-full ${index === 0 ? 'bg-yellow-100 text-yellow-800' : index === 1 ? 'bg-gray-100 text-gray-800' : index === 2 ? 'bg-orange-100 text-orange-800' : 'bg-blue-100 text-blue-800'}">
                                ${index + 1}
                            </div>
                        </div>
                    </td>
                    <td class="px-6 py-4 whitespace-nowrap">
                        <div class="text-sm font-medium text-gray-900">${stats.count}</div>
                    </td>
                    <td class="px-6 py-4 whitespace-nowrap">
                        <div class="text-sm text-gray-900">${safeAvgTime.toFixed(2)}s</div>
                    </td>
                    <td class="px-6 py-4 whitespace-nowrap">
                        <div class="text-sm text-gray-900">${safeTotalTime.toFixed(2)}s</div>
                    </td>
                    <td class="px-6 py-4 whitespace-nowrap">
                        <div class="w-full bg-gray-200 rounded-full h-2">
                            <div class="bg-primary h-2 rounded-full" style="width: ${percentage}%"></div>
                        </div>
                        <div class="text-xs text-gray-500 mt-1">${percentage}%</div>
                    </td>
                    <td class="px-6 py-4">
                        <div class="text-sm font-mono max-h-20 overflow-y-auto">${stats.sql}</div>
                    </td>
                `;
                
                // 添加行点击事件
                row.addEventListener('click', () => {
                    // 移除所有行的高亮
                    document.querySelectorAll('#statsTable tr').forEach(r => {
                        r.classList.remove('highlight-row');
                    });
                    
                    // 添加当前行高亮
                    row.classList.add('highlight-row');
                    
                    // 在输出区域显示详细信息
                    const details = stats.queries.map((q, i) => `
查询 ${i + 1}: Count=${q.count}, Time=${q.singleTime}s (${q.time}s)
${formatSQL(q.sql)}
                    `).join('\n\n');
                    
                    sqlOutput.textContent = details;
                    outputCharCount.textContent = `${details.length} 字符`;
                });
                
                statsTable.appendChild(row);
            });
        }
        
        // 复制到剪贴板
        function copyToClipboard(text, message = '已复制到剪贴板') {
            navigator.clipboard.writeText(text).then(() => {
                showNotification(message, 'success');
            }).catch(err => {
                showNotification('复制失败，请手动复制', 'error');
                console.error('复制失败:', err);
            });
        }
        
        // 显示通知
        function showNotification(message, type = 'info') {
            // 移除已有的通知
            const existingNotification = document.querySelector('.notification');
            if (existingNotification) {
                existingNotification.remove();
            }
            
            // 创建通知元素
            const notification = document.createElement('div');
            notification.className = 'notification fixed top-4 right-4 px-4 py-2 rounded-md shadow-lg z-50 transform transition-all duration-300';
            
            // 根据类型设置样式
            if (type === 'success') {
                notification.classList.add('bg-green-500', 'text-white');
                notification.innerHTML = `<i class="fa fa-check-circle mr-2"></i>${message}`;
            } else if (type === 'error') {
                notification.classList.add('bg-red-500', 'text-white');
                notification.innerHTML = `<i class="fa fa-exclamation-circle mr-2"></i>${message}`;
            } else if (type === 'warning') {
                notification.classList.add('bg-yellow-500', 'text-white');
                notification.innerHTML = `<i class="fa fa-exclamation-triangle mr-2"></i>${message}`;
            } else {
                notification.classList.add('bg-blue-500', 'text-white');
                notification.innerHTML = `<i class="fa fa-info-circle mr-2"></i>${message}`;
            }
            
            // 添加到页面
            document.body.appendChild(notification);
            
            // 动画效果
            setTimeout(() => {
                notification.classList.add('opacity-0');
                setTimeout(() => notification.remove(), 300);
            }, 3000);
        }
        
        // 下载文本为文件
        function downloadTextAsFile(text, filename) {
            const blob = new Blob([text], { type: 'text/plain' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            URL.revokeObjectURL(url);
        }
        
        // 导出表格数据
        function exportTableData(statsArray, totalTime) {
            if (!statsArray || statsArray.length === 0) {
                showNotification('没有可导出的统计数据', 'warning');
                return;
            }
            
            // 创建CSV内容
            let csvContent = '排名,执行次数,平均时间(秒),总时间(秒),百分比,脱敏后SQL\n';
            
            statsArray.forEach((stats, index) => {
                const safeAvgTime = isNaN(stats.avgTime) ? 0 : stats.avgTime;
                const safeTotalTime = isNaN(stats.totalTime) ? 0 : stats.totalTime;
                const percentage = totalTime > 0 ? ((safeTotalTime / totalTime) * 100).toFixed(1) : 0;
                
                // 转义SQL中的引号
                const escapedSQL = stats.sql.replace(/"/g, '""');
                csvContent += `${index + 1},${stats.count},${safeAvgTime.toFixed(2)},${safeTotalTime.toFixed(2)},${percentage}%,"${escapedSQL}"\n`;
            });
            
            // 下载CSV文件
            const timestamp = new Date().toISOString().slice(0, 19).replace(/[:-]/g, '').replace('T', '_');
            downloadTextAsFile(csvContent, `sql_stats_${timestamp}.csv`);
            showNotification('统计表格已导出', 'success');
        }
        
        // 排序处理函数
        function handleSort(header) {
            const newField = header.getAttribute('data-sort');
            
            // 切换排序方向
            if (sortField === newField) {
                sortAsc = !sortAsc;
            } else {
                sortField = newField;
                sortAsc = false; // 新字段默认降序
            }
            
            // 更新排序图标
            sortHeaders.forEach(h => {
                h.classList.remove('sort-asc', 'sort-desc');
            });
            header.classList.add(sortAsc ? 'sort-asc' : 'sort-desc');
            
            // 重新排序并渲染表格
            const sortedArray = [...currentStatsArray].sort((a, b) => {
                // 确保比较的值是有效数字
                const aVal = isNaN(a[sortField]) ? 0 : a[sortField];
                const bVal = isNaN(b[sortField]) ? 0 : b[sortField];
                
                if (sortField === 'count') return sortAsc ? aVal - bVal : bVal - aVal;
                if (sortField === 'avgTime') return sortAsc ? aVal - bVal : bVal - aVal;
                if (sortField === 'totalTime') return sortAsc ? aVal - bVal : bVal - aVal;
                if (sortField === 'percentage') {
                    const aPercent = currentTotalTime > 0 ? (a.totalTime / currentTotalTime) * 100 : 0;
                    const bPercent = currentTotalTime > 0 ? (b.totalTime / currentTotalTime) * 100 : 0;
                    return sortAsc ? aPercent - bPercent : bPercent - aPercent;
                }
                return 0;
            });
            
            renderStatsTable(sortedArray, currentTotalTime);
        }
        
        // 事件监听器
        desensitizeBtn.addEventListener('click', performDesensitization);
        
        exampleBtn.addEventListener('click', () => {
            sqlInput.value = exampleSQL;
            updateCharCount();
            showNotification('已加载示例SQL', 'info');
        });
        
        formatBtn.addEventListener('click', () => {
            if (!sqlInput.value.trim()) {
                showNotification('请输入SQL语句', 'warning');
                return;
            }
            
            // 尝试解析SQL组
            let input = sqlInput.value;
            input = input.replace(/Lock=[\d.]+s\s*\([\d.]+\s*s\)/g, '')
                         .replace(/Rows=[\d.]+\s*\([\d.]+\)/g, '')
                         .replace(/nfo\[.*?\]@\[.*?\]/g, '')
                         .replace(/\s+/g, ' ').trim();
            
            const sqlGroups = parseSQLGroups(input);
            
            if (sqlGroups.length > 0) {
                // 如果是SQL组，格式化每个SQL
                const formatted = sqlGroups.map(group => {
                    return `Count: ${group.count}  Time=${group.singleTime}s (${group.time}s)\n${formatSQL(group.sql)}\n\n`;
                }).join('').trim();
                
                sqlInput.value = formatted;
            } else {
                // 否则格式化整个输入
                sqlInput.value = formatSQL(input);
            }
            
            updateCharCount();
            showNotification('SQL已格式化', 'success');
        });
        
        copyBtn.addEventListener('click', () => {
            if (!sqlOutput.textContent.trim()) {
                showNotification('没有可复制的结果', 'warning');
                return;
            }
            
            copyToClipboard(sqlOutput.textContent);
        });
        
        copyResultBtn.addEventListener('click', () => {
            if (!sqlOutput.textContent.trim()) {
                showNotification('没有可复制的结果', 'warning');
                return;
            }
            
            const originalLen = sqlInput.value.length;
            const desensitizedLen = sqlOutput.textContent.length;
            const paramCount = parseInt(parameterCount.textContent);
            const rate = compressionRate.textContent;
            
            const resultSummary = `
原始SQL长度: ${originalLen} 字符
脱敏后长度: ${desensitizedLen} 字符
替换参数数量: ${paramCount}
压缩率: ${rate}
总查询数: ${totalQueries.textContent}
唯一SQL数: ${uniqueQueries.textContent}
脱敏后SQL:
${sqlOutput.textContent}
            `.trim();
            
            copyToClipboard(resultSummary, '结果已复制到剪贴板');
        });
        
        clearBtn.addEventListener('click', () => {
            sqlInput.value = '';
            sqlOutput.textContent = '';
            statsMap = new Map();
            currentStatsArray = [];
            currentTotalTime = 0;
            statsTable.innerHTML = `
                <tr>
                    <td colspan="6" class="px-6 py-12 text-center text-gray-500">
                        <div class="flex flex-col items-center">
                            <i class="fa fa-bar-chart text-4xl mb-4 text-gray-300"></i>
                            <p>执行脱敏后，统计结果将显示在这里</p>
                        </div>
                    </td>
                </tr>
            `;
            updateCharCount();
            outputCharCount.textContent = '0 字符';
            updateStats('', '', 0);
            totalQueries.textContent = '0';
            uniqueQueries.textContent = '0';
            showNotification('已清空所有内容', 'info');
        });
        
        downloadBtn.addEventListener('click', () => {
            if (!sqlOutput.textContent.trim()) {
                showNotification('没有可下载的结果', 'warning');
                return;
            }
            
            const timestamp = new Date().toISOString().slice(0, 19).replace(/[:-]/g, '').replace('T', '_');
            downloadTextAsFile(sqlOutput.textContent, `desensitized_sql_${timestamp}.sql`);
            showNotification('SQL已下载', 'success');
        });
        
        exportTableBtn.addEventListener('click', () => {
            exportTableData(currentStatsArray, currentTotalTime);
        });
        
        sqlInput.addEventListener('input', updateCharCount);
        
        // 排序表头事件
        sortHeaders.forEach(header => {
            header.addEventListener('click', () => handleSort(header));
        });
        
        // 支持按Ctrl+Enter执行脱敏
        sqlInput.addEventListener('keydown', (e) => {
            if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
                e.preventDefault();
                performDesensitization();
            }
        });
        
        // 初始化
        updateCharCount();
        updateStats('', '', 0);
    </script>
</body>
</html>